Imports System.IO
Imports System.IO.IsolatedStorage
Imports System.Xml.Serialization


Friend Class IsolatedStoragePreferencesNode : Inherits AbstractPreferencesNode
    Private Const mPathSeparatorChar As Char = "\\"
    Private Const mStarWildcard As String = "*"

    Private Shared ReadOnly mSystemRootNode As IPreferencesNode
    Private Shared ReadOnly mUserRootNode As IPreferencesNode
    Private ReadOnly mRepresentative As IsolatedStorageFile
    Private ReadOnly mPrefix As String

    Shared Sub New()
        Try
            mSystemRootNode = Nothing
            mUserRootNode = New IsolatedStoragePreferencesNode(Nothing, String.Empty, False)
        Catch ex As Exception
            Throw New PreferencesStorageException(Res.ISPN_Init, ex)
        End Try
    End Sub

    Friend Shared ReadOnly Property SystemRootNode() As IPreferencesNode
        Get

            Return mSystemRootNode
        End Get
    End Property

    Friend Shared ReadOnly Property UserRootNode() As IPreferencesNode
        Get
            Return mUserRootNode
        End Get
    End Property


    ''' <summary>
    ''' Set the parent, the name, and the appName. App name is the application that
    ''' uses this library's name. This application name is used so that applications
    ''' don't trample one another's user preferences in user's Application Data 
    ''' directory.
    ''' </summary>
    ''' <param name="parent">The parent node of this node.</param>
    ''' <param name="name">The name of this node.</param>
    ''' <param name="appName">The name of the application calling this library.</param>
    Friend Sub New(ByVal parent As AbstractPreferencesNode, ByVal name As String, ByVal isSystemNode As Boolean)
        MyBase.New(parent, name, False)
        Try
            mRepresentative = IsolatedStorageFile.GetUserStoreForDomain()
            Dim directoryAbsolutePath As String = AbsolutePath.Replace( _
              AbstractPreferencesNode.PathSeparatorChar, PathSeparatorChar)
            mRepresentative.CreateDirectory(directoryAbsolutePath)
            mPrefix = directoryAbsolutePath + PathSeparatorChar
        Catch ex As Exception
            Throw New PreferencesStorageException(Res.ISPN_Create, ex)
        End Try
    End Sub

    Protected Overrides Function StorageGetChildNodeForPath(ByVal childNodeName As String) As IPreferencesNode
        Return New IsolatedStoragePreferencesNode(Me, childNodeName, IsSystemNode)
    End Function

    Protected Overrides Sub StorageSynchronize()
        '' do nothing
    End Sub

    Protected Overrides Function StorageGetBinary(ByVal key As String) As Byte()
        Dim fullKey As String = mPrefix + key
        Dim fileNames As String() = mRepresentative.GetFileNames(fullKey)

        If Not CType(fileNames, IList).Contains(key) Then Return Nothing

        Dim streamFromKey As Stream
        streamFromKey = New IsolatedStorageFileStream(fullKey, FileMode.Open, FileAccess.Read, mRepresentative)

        Dim binReader As BinaryReader = New BinaryReader(streamFromKey)

        Dim contents(streamFromKey.Length - 1) As Byte
        binReader.Read(contents, 0, streamFromKey.Length)
        binReader.Close()
        Return contents
    End Function

    Protected Overrides Function StorageGetSerializedObject(ByVal key As String, ByVal serializer As XmlSerializer) As Object
        Dim fullKey As String = mPrefix + key
        Dim fileNames As String() = mRepresentative.GetFileNames(fullKey)

        If Not CType(fileNames, IList).Contains(key) Then Return Nothing

        Dim streamFromKey As Stream = New IsolatedStorageFileStream(fullKey, FileMode.Open, FileAccess.Read, mRepresentative)

        ''IFormatter formatter = new BinaryFormatter();
        ''object deserializedObject = formatter.Deserialize(streamFromKey);
        Dim deserializedObject As Object = serializer.Deserialize(streamFromKey)
        streamFromKey.Close()
        Return deserializedObject
    End Function

    Protected Overrides Function StorageGetText(ByVal key As String) As String
        Dim fullKey As String = mPrefix + key
        Dim fileNames() As String = mRepresentative.GetFileNames(fullKey)

        If Not CType(fileNames, IList).Contains(key) Then Return Nothing

        Dim streamFromKey As Stream = New IsolatedStorageFileStream(fullKey, FileMode.Open, FileAccess.Read, mRepresentative)
        Dim textReader As textReader = New StreamReader(streamFromKey)
        Dim text As String = textReader.ReadToEnd()
        textReader.Close()

        Return text
    End Function

    Protected Overrides Function StorageKeys() As String()
        Return mRepresentative.GetFileNames(mPrefix + mStarWildcard)
    End Function

    Protected Overrides Sub StoragePutBinary(ByVal key As String, ByVal val As Byte())
        Dim fullKey As String = mPrefix + key
        Dim streamToKey As Stream = New IsolatedStorageFileStream(fullKey, FileMode.Create, FileAccess.Write, mRepresentative)
        Dim binWriter As BinaryWriter = New BinaryWriter(streamToKey)
        binWriter.Write(val)
        binWriter.Close()
    End Sub

    Protected Overrides Sub StoragePutSerializableObject(ByVal key As String, ByVal val As Object)
        Dim fullKey As String = mPrefix + key
        Dim streamToKey As Stream = New IsolatedStorageFileStream(fullKey, FileMode.Create, FileAccess.Write, mRepresentative)

        ''IFormatter formatter = new BinaryFormatter();
        ''formatter.Serialize(streamToKey, val);
        Dim serializer As XmlSerializer = New XmlSerializer(val.GetType())
        serializer.Serialize(streamToKey, val)
        streamToKey.Close()
    End Sub

    Protected Overrides Sub StoragePutText(ByVal key As String, ByVal val As String)
        Dim fullKey As String = mPrefix + key
        Dim streamToKey As Stream = New IsolatedStorageFileStream(fullKey, FileMode.Create, FileAccess.Write, mRepresentative)
        Dim textWriter As textWriter = New StreamWriter(streamToKey)

        textWriter.Write(val)
        textWriter.Close()
    End Sub

    Protected Overrides Sub StorageRemoveAllPreferencesFromNode()

        Dim fileNames As String() = mRepresentative.GetFileNames(mPrefix + mStarWildcard)
        For Each fileName As String In fileNames
            mRepresentative.DeleteFile(mPrefix + fileName)
        Next
    End Sub

    Protected Overrides Sub StorageRemoveNode()
        RemoveNodeRecursive(AbsolutePath.Replace(AbstractPreferencesNode.PathSeparatorChar, mPathSeparatorChar))
    End Sub

    Private Sub RemoveNodeRecursive(ByVal directoryPath As String)
        '' This is a bit more complex for isolated storage because
        '' IsolatedStorage only allow us to delete a dir if it's empty
        Dim directoryPrefix As String = directoryPath + mPathSeparatorChar
        Dim fileNames As String() = mRepresentative.GetFileNames(directoryPrefix + mStarWildcard)
        For Each fileName As String In fileNames
            mRepresentative.DeleteFile(directoryPrefix + fileName)
        Next

        Dim subDirNames As String() = mRepresentative.GetDirectoryNames(directoryPrefix + mStarWildcard)
        For Each subDirName As String In subDirNames
            RemoveNodeRecursive(directoryPrefix + subDirName)
        Next
        mRepresentative.DeleteDirectory(directoryPath)
        mRepresentative.Close()
    End Sub

    Protected Overrides Function StorageRemovePreferenceFromNode(ByVal key As String) As Boolean
        Dim fullKey As String = mPrefix + key
        Dim fileNames As String() = mRepresentative.GetFileNames(fullKey)

        If Not CType(fileNames, IList).Contains(key) Then Return False

        mRepresentative.DeleteFile(fullKey)
        Return True
    End Function

End Class
